import globalConfig

class Elevator:
    def __init__(self):
        self.max_floor = globalConfig.max_floor
        self.req_que = []
        self.cur_floor = 1.0
        # 速度为每时间步上升/下降多少层
        self.speed = 0.2
        self.wait = 0
        self.height_per_floor = 3
        self.door = True
        self.avail = True
        self.tar_floor = None
        self.direction = 0
        self.carried = []
        self.max_capacity = 10  # 新增容量限制

    def down(self):
        self.cur_floor = round(self.cur_floor - self.speed, 10)
        print('elevator goes down...')

    def up(self):
        self.cur_floor = round(self.cur_floor + self.speed, 10)
        print('elevator goes up...')

    def arr(self):
        print('elevator has arrived...')
        self.open_door()
        # 更新tar_floor
        self.check_passengers()
        if self.set_target_floor():
            if self.set_direction():
                self.check_passengers()
                self.set_target_floor()
        self.wait += 1

    def open_door(self):
        print('open door')
        if self.door:
            self.door = False

    def close_door(self):
        print('close door')
        self.door = True
        self.wait = 0

    # 检查电梯需求列表，有没有人上，有没有人下
    def check_passengers(self):
        # global sum_time
        # global finished_p
        # global time_count
        print('Check the status of passengers')
        print('Request list：', [p.id for p in self.req_que])
        print('Elevator passengers：', [p.id for p in self.carried])
        for p in self.carried[:]:
            if p.arr_floor == self.cur_floor:
                print('Passenger {0} gets off the elevator'.format(p.id))
                p.arr_time = globalConfig.time_count
                globalConfig.sum_time += p.arr_time - p.req_time
                globalConfig.finished_p += 1
                self.carried.remove(p)
        for p in self.req_que[:]:
            if len(self.carried) >= self.max_capacity:
                break

            if p.req_floor == self.cur_floor:
                if self.direction != 0:
                    if p.direction == self.direction:
                        print('Passenger {0} gets on the elevator'.format(p.id))
                        globalConfig.wait_time += globalConfig.time_count - p.req_time
                        self.req_que.remove(p)
                        self.carried.append(p)
                    elif not self.carried:
                        print('Passenger {0} gets on the elevator'.format(p.id))
                        globalConfig.wait_time += globalConfig.time_count - p.req_time
                        self.req_que.remove(p)
                        self.carried.append(p)
                else:
                    print('Passenger {0} gets on the elevator'.format(p.id))
                    globalConfig.wait_time += globalConfig.time_count - p.req_time
                    self.req_que.remove(p)
                    self.carried.append(p)

    # 检查需求，设定目标楼层
    def set_target_floor(self):
        print('Find the target floor and the direction of the current elevator:{}'.format(self.direction))
        self.tar_floor = None
        min_req_dis = None
        min_arr_dis = None

        # 检查电梯外部请求
        req_dis_list = []
        req_que_select = []
        if self.req_que[:]:
            for p in self.req_que:
                if p.req_floor == self.cur_floor and self.carried:
                    continue
                else:
                    req_que_select.append(p)
                    req_dis_list.append(self.alloc_cost(p.req_floor, p.direction))
                min_req_dis = min(req_dis_list)
        # 检查电梯内部请求
        if self.carried:
            arr_dis_list = [self.get_distance(p.arr_floor) for p in self.carried]
            min_arr_dis = min(arr_dis_list)

        # 获取最近的需求层
        if min_arr_dis is not None and min_req_dis is not None:
            if min_arr_dis < min_req_dis:
                self.tar_floor = self.carried[arr_dis_list.index(min_arr_dis)].arr_floor
                print('tar_floor：{}'.format(self.tar_floor))
            else:
                self.tar_floor = req_que_select[req_dis_list.index(min_req_dis)].req_floor
                print('tar_floor：{}'.format(self.tar_floor))
            return True
        elif min_arr_dis is not None:
            self.tar_floor = self.carried[arr_dis_list.index(min_arr_dis)].arr_floor
            print('tar_floor：{}'.format(self.tar_floor))
            return True
        elif min_req_dis is not None:
            self.tar_floor = req_que_select[req_dis_list.index(min_req_dis)].req_floor
            print('tar_floor：{}'.format(self.tar_floor))
            return True
        else:
            print('no target')
            return False

    # 计算请求楼层和当前楼层的距离
    def get_distance(self, req_floor):
        if self.direction == 1:
            if self.cur_floor > req_floor:
                return self.max_floor - self.cur_floor + self.max_floor - req_floor
            else:
                return req_floor - self.cur_floor
        elif self.direction == -1:
            if self.cur_floor > req_floor:
                return self.cur_floor - req_floor
            else:
                return self.cur_floor - 1 + req_floor - 1
        else:
            return abs(self.cur_floor - req_floor)

    def set_direction(self):
        old_direction = self.direction
        if self.tar_floor:
            if self.tar_floor > self.cur_floor:
                self.direction = 1
            elif self.tar_floor < self.cur_floor:
                self.direction = -1
            elif not self.carried:
                self.direction = 0
        else:
            self.direction = 0
        if self.direction != old_direction:
            print('change direction：{}'.format(self.direction))
            return True
        else:
            return False

    # 计算电梯分配成本
    def alloc_cost(self, req_floor, direction):
        overload_penalty = 0
        if len(self.req_que) - 8 > 0:
            overload_penalty += (len(self.req_que) - 8) * 1.0

        if self.direction == 1:
            if self.cur_floor > req_floor or direction == -1:
                return self.max_floor - self.cur_floor + self.max_floor - req_floor + overload_penalty
            else:
                return req_floor - self.cur_floor + overload_penalty
        elif self.direction == -1:
            if self.cur_floor < req_floor or direction == 1:
                return self.cur_floor - 1 + req_floor - 1 + overload_penalty
            else:
                return self.cur_floor - req_floor + overload_penalty
        else:
            return abs(self.cur_floor - req_floor) + overload_penalty